#include "SipClnInviteTrans.hpp"

#include "resip/stack/Helper.hxx"
#include "SipUserAgent.hpp"
#include "SipDialog.hpp"

namespace wtsip{

CSipClnInviteTrans::CSipClnInviteTrans(SipMessage& request, CSipUserAgent& ua): 
CSipClnTransaction(request, ua), m_invCallback(0)
{
    m_State = InvClnInitial;
}

CSipClnInviteTrans::~CSipClnInviteTrans()
{
}


bool CSipClnInviteTrans::setState(int state){
    m_State = state;
    if (m_invCallback){
        m_invCallback->onStateChange(*this, state);
    }
    return true;
}


bool CSipClnInviteTrans::send(std::auto_ptr<SipMessage> msg){
    if (msg.get() && msg->isRequest()){
        MethodTypes m = msg->header(h_RequestLine).method();
        if (resip::INVITE == m){
            if (InvClnInitial == m_State || InvClnInvite == m_State){
                if (InvClnInvite != m_State){
                    setState(InvClnInvite);
                }
                m_ua.send(msg);
            }
        } else if (resip::CANCEL == m){
            if (InvClnInvite == m_State || InvClnTrying == m_State || InvClnCancel == m_State){
                if (InvClnCancel != m_State){
                    setState(InvClnCancel);
                }
                m_ua.send(msg);
            }
        } else if (resip::ACK == m){
            if (InvClnFailed == m_State){
                m_ua.send(msg);
            }
        }
    }
    return true;
}


bool CSipClnInviteTrans::processIncoming(SipMessage* msg){
    if (!msg)
        return false;

    assert(msg->isResponse());
    assert(m_mth == msg->method());
    
    int code = msg->header(h_StatusLine).responseCode();
    int hCode = code / 100;
    if (hCode == 1){
        if (InvClnInvite == m_State){
            setState(InvClnTrying);
            if (m_invCallback){
                m_invCallback->onTrying(*this, *msg);
            }
        }
    } else if (2 == hCode){
        if (InvClnCancel == m_State){
            setState(InvClnCanceled);
            if (m_invCallback){
                m_invCallback->onCanceled(*this, *msg);
            }
        } else if (InvClnInvite == m_State || InvClnTrying == m_State){
            setState(InvClnSuccessed);
            if (m_invCallback){
                m_invCallback->onSuccessed(*this, *msg);
            }
        }
    } else if (4 == hCode){
        if (InvClnInvite == m_State || InvClnTrying == m_State || InvClnCanceled == m_State)
        {
            setState(InvClnFailed);
            if (m_invCallback){
                m_invCallback->onFailed(*this, *msg);
            }
        }
    }
    return true;
}


bool CSipClnInviteTrans::registerInvCallback(CSipClnInviteTransCallback* callback){
    m_invCallback = callback;
    return true;
}


bool CSipClnInviteTrans::unregisterInvCallback(){
    m_invCallback = NULL;
    return true;
}


SipMessage* CSipClnInviteTrans::createCancel(){
    SipMessage* cancel = Helper::makeCancel(m_request);
    return cancel;
}


SipMessage* CSipClnInviteTrans::createFailAck()
{
    assert (m_request.header(h_RequestLine).getMethod() == INVITE);
    assert (m_bindDialog);

    SipMessage* ack = new SipMessage();

    RequestLine rLine(ACK, m_request.header(h_RequestLine).getSipVersion());
    rLine.uri() = m_request.header(h_RequestLine).uri();
    ack->header(h_RequestLine) = rLine;
    ack->header(h_MaxForwards).value() = 70;
    ack->header(h_CallId) = m_request.header(h_CallId);
    ack->header(h_From) = m_request.header(h_From);
    ack->header(h_To) = m_bindDialog->getRemoteNameAddr();
    ack->header(h_Vias).push_back(m_request.header(h_Vias).front());
    ack->header(h_CSeq) = m_request.header(h_CSeq);
    ack->header(h_CSeq).method() = ACK;

    return ack;
}



}//namespace

